package com.soviet.boot.common.utils;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.SimpleAutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.builder.GeneratorBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.baomidou.mybatisplus.generator.fill.Property;
import freemarker.template.Configuration;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.*;

/**
 * @Author Dave
 * @Date 2021/7/19
 * @Description
 */
@Component
public class CodeGenerator {

    private static final String ROOT_DIR = System.getProperty("user.dir");

    //文档地址: https://github.com/baomidou/generator
    public void generator(GeneratorHelper generatorHelper) {
        new SimpleAutoGenerator() {
            @Override
            public IConfigBuilder<DataSourceConfig> dataSourceConfigBuilder() {
                return new DataSourceConfig.Builder(generatorHelper.getJdbcUrl(),
                        generatorHelper.getJdbcUser(), generatorHelper.getJdbcPassword());
            }

            @Override
            public IConfigBuilder<InjectionConfig> injectionConfigBuilder() {
                return new InjectionConfig.Builder()
                        .beforeOutputFile((k, v) -> {
                            v.put("abc", "dave");
                            v.put("auth", generatorHelper.getAuth());
                        });
            }

            @Override
            public IConfigBuilder<GlobalConfig> globalConfigBuilder() {
                // 全局配置
                return GeneratorBuilder.globalConfigBuilder()
                        .fileOverride()
                        .openDir(true)
                        .outputDir(ROOT_DIR + "/generate/backend/src/main/java")
                        .author(generatorHelper.getAuthor())
                        .enableSwagger()
                        .commentDate("yyyy/MM/dd");
            }

            @Override
            public IConfigBuilder<PackageConfig> packageConfigBuilder() {
                return new PackageConfig.Builder()
                        .parent(generatorHelper.getParent())
                        .moduleName(generatorHelper.getModule());
            }

            @Override
            public IConfigBuilder<TemplateConfig> templateConfigBuilder() {
                return new TemplateConfig.Builder()
                        .controller("/templates/backend/controller.java");
            }

            @Override
            public AbstractTemplateEngine templateEngine() {
                return new FreemarkerTemplateEngine() {
                    @Override
                    public AbstractTemplateEngine batchOutput() {
                        AbstractTemplateEngine abstractTemplateEngine = super.batchOutput();
                        ConfigBuilder config = this.getConfigBuilder();
                        config.getTableInfoList()
                                .forEach(e -> {
                                    Map<String, Object> objectMap = this.getObjectMap(config, e);
                                    Optional.ofNullable(config.getInjectionConfig()).ifPresent((t) -> {
                                        t.beforeOutputFile(e, objectMap);
                                    });
                                    Map<String, Object> customFiles = new HashMap<>();
                                    customFiles.put("/templates/fronts/crud.jsx.ftl", "/crud.jsx");
                                    customFiles.put("/templates/fronts/index.vue.ftl", "/index.vue");
                                    customFiles.put("/templates/fronts/api.js.ftl", "/api.js");
                                    customFiles.put("/templates/fronts/router.js.ftl", "/router.js");
                                    //customFiles.put("/templates/sql/resource.sql.ftl", "_menu.sql");
                                    customFiles.forEach((t, v) -> {
                                        String dir = "/front";
                                        if (t.endsWith("sql.ftl")) {
                                            dir = "/sql";
                                        }
                                        String fileName = ROOT_DIR + "/generate" + dir + "/views/" + e.getEntityName() + v;
                                        this.outputFile(new File(fileName), objectMap, t);

                                    });
                                });
                        return abstractTemplateEngine;
                    }
                };
            }

            @Override
            public IConfigBuilder<StrategyConfig> strategyConfigBuilder() {
                return new StrategyConfig.Builder()
                        .addInclude(generatorHelper.getTables().split(","))
                        .disableSqlFilter()// 启用sql过滤
                        .enableCapitalMode()// 是否大写命名
                        .entityBuilder()// 实体配置构建者
                        .enableLombok()// 开启lombok模型
                        .versionColumnName("version") //乐观锁数据库表字段
                        .naming(NamingStrategy.underline_to_camel)// 数据库表映射到实体的命名策略
                        .addTableFills(new Column("create_time", FieldFill.INSERT))    //基于数据库字段填充
                        .addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE))    //基于模型属性填充
                        .controllerBuilder() //控制器属性配置构建
                        .enableRestStyle()
                        // 实体配置
                        .entityBuilder()
                        .logicDeletePropertyName("isDel") //逻辑删除字段
                        .idType(IdType.ASSIGN_ID) //全局id策略
                        .mapperBuilder()
                        .enableBaseColumnList()
                        .enableBaseResultMap();

            }
        }.execute();
    }

}
